import { Object3D } from "../../../../../entity/Object3D";
import { Mesh } from "../../../../../component/Mesh";
import { Matrix4 } from "../../../../../core/math/Matrix4";
import { StandardMaterial } from "../../../../../material/StandardMaterial";
import { getTexturesObject } from "../../../gltf/util";
import { Geometry } from "../../../../../geom/Geometry";
import { Group } from "../../../../../scene/Group";
import { generateUUID } from "../../../../../core/math/MathUtils";

let zUpToYUpMatrix = new Matrix4();
zUpToYUpMatrix.set(
  1, 0, 0, 0,
  0, 0, -1, 0,
  0, 1, 0, 0,
  0, 0, 0, 1);
class GltfObject {
  constructor(gltf, key,worldMatrix) {
    this.materialMap = new Map()
    this.id = key
    // this.id = key+generateUUID()
    this.b3dmNode = new Object3D({ id:this.id });
    const trans = this.b3dmNode.trans;
    trans.applyMatrix4(worldMatrix);
    trans.applyMatrix4(zUpToYUpMatrix);
    this.createMaterial(gltf)
    const primitives = gltf.primitives
    for (let index = 0; index < primitives.length; index++) {
      const element = primitives[index];
      const geometry = new Geometry();
      geometry.boundingBox= element.geometry.boundingBox
      if (element.geometry.position) {
        geometry["position"] = element.geometry.position;
      }
      if (element.geometry.indices) {
        geometry["indices"] = element.geometry.indices;
      }
      if (element.geometry.normal) {
        geometry["normal"] = element.geometry.normal;
      }
      if (element.geometry.texCood1) {
        geometry["texCood1"] = element.geometry.texCood1;
      }
      if (element.geometry.texCood0) {
        geometry["texCood0"] = element.geometry.texCood0;
      }
      if (element.geometry.color) {
        geometry["color"] = element.geometry.color;
        geometry.colorStep=element.geometry.colorsStep
      }
      if (element.geometry.tangents) {
        geometry["tangent"] = element.geometry.tangents;
      }
      let standardMaterial = this.materialMap.get(element.material);
      if (!standardMaterial) {
        standardMaterial = new StandardMaterial({ metallicRoughnessMap: null });
      }
      let id = this.id + `${index}`
      const meshCom = new Mesh({ geometry, material: standardMaterial });
      const primitive = new Object3D({ id:id });
      primitive.addComponent(meshCom);
      primitive.trans.applyMatrix4(element.worldMatrix);
      this.b3dmNode.add(primitive);
    }
    // this.group.addEntity(b3dmRootNode)
  }
  createMaterial (gltf) {
    if (!gltf.materials) {
      return;
    }
    const materials = gltf.materials;
    materials.map((material, index) => {
      let { alphaMode, doubleSided, emissiveFactor, pbrMetallicRoughness, name, alphaCutoff } =
        material;
      let { baseColorFactor, metallicFactor, roughnessFactor } = pbrMetallicRoughness;
      const textureIndex = getTexturesObject(material);
      const {
        baseColorTexture,
        metallicRoughnessTexture,
        normalTexture,
        occlusionTexture,
        emissiveTexture,
      } = textureIndex;
      var mapUvTransform,
        emissiveMapUvTransform,
        metallicRoughnessMapUvTransform,
        normalMapUvTransform,
        aoMap_uvTransform;
      if (baseColorTexture?.extensions?.KHR_texture_transform) {
        mapUvTransform = this.generateUvTransform(
          baseColorTexture.extensions.KHR_texture_transform
        );
      }
      if (metallicRoughnessTexture?.extensions?.KHR_texture_transform) {
        metallicRoughnessMapUvTransform = this.generateUvTransform(
          metallicRoughnessTexture.extensions.KHR_texture_transform
        );
      }
      if (normalTexture?.extensions?.KHR_texture_transform) {
        normalMapUvTransform = this.generateUvTransform(
          normalTexture.extensions.KHR_texture_transform
        );
      }
      if (occlusionTexture?.extensions?.KHR_texture_transform) {
        aoMap_uvTransform = this.generateUvTransform(
          occlusionTexture.extensions.KHR_texture_transform
        );
      }
      if (emissiveTexture?.extensions?.KHR_texture_transform) {
        emissiveMapUvTransform = this.generateUvTransform(
          emissiveTexture.extensions.KHR_texture_transform
        );
      }
      let alphaTest = 0;
      let blend;
      let transparent = false;
      if (alphaMode === "BLEND") {
        blend = {
          alphaSrcFactor: "one",
          alphaDstFactor: "one",
          alphaOperation: "add",
          colorSrcFactor: "src-alpha",
          colorDstFactor: "one-minus-src-alpha",
          colorOperation: "add",
        };
        transparent = true;
      }
      if (alphaMode === "MASK" && !alphaCutoff) {
        alphaCutoff = 0.5;
      }
      const textureArray = gltf.images;
      const imagesNames = gltf.imagesNames;
      for (let i = 0; i < textureArray.length; i++) {
        const element = textureArray[i];
        element.id=imagesNames[i]
      }
      let standardMaterial = new StandardMaterial({
        name: material.name,
        color: baseColorFactor,
        alphaCutoff: alphaCutoff,
        alphaSrcFactor: blend?.alphaSrcFactor,
        alphaDstFactor: blend?.alphaDstFactor,
        alphaOperation: blend?.alphaOperation,
        colorSrcFactor: blend?.colorSrcFactor,
        colorDstFactor: blend?.colorDstFactor,
        colorOperation: blend?.colorOperation,
        metalness: metallicFactor,
        roughness: roughnessFactor,
        emissive: emissiveFactor,
        emissiveMap: emissiveTexture
          ? {
            sampler: emissiveTexture.sampler,
            url: emissiveTexture ? textureArray[emissiveTexture.source] : null,
            uvIndex: emissiveTexture?.texCoord || 0,
            uvTransform: emissiveMapUvTransform,
            mipMap:false,
            isCache:false
          }
          : undefined,

          metRougMap: metallicRoughnessTexture
          ? {
            sampler: metallicRoughnessTexture.sampler,
            url: metallicRoughnessTexture ? textureArray[metallicRoughnessTexture.source] : null,
            uvIndex: metallicRoughnessTexture?.texCoord || 0,
            uvTransform: metallicRoughnessMapUvTransform,
            mipMap:false,
            isCache:false
          }
          : undefined,
        normalMap: normalTexture
          ? {
            sampler: normalTexture.sampler,
            url: normalTexture ? textureArray[normalTexture.source] : null,
            uvIndex: normalTexture?.texCoord || 0,
            uvTransform: normalMapUvTransform,
            mipMap:false,
            isCache:false
          }
          : undefined,
        map: baseColorTexture
          ? {
            sampler: baseColorTexture.sampler,
            url: baseColorTexture ? textureArray[baseColorTexture.source] : null,
            uvIndex: baseColorTexture?.texCoord || 0,
            uvTransform: mapUvTransform,
            mipMap:false,
            isCache:false
          }
          : undefined,
        aoMap: occlusionTexture
          ? {
            sampler: occlusionTexture.sampler,
            url: occlusionTexture ? textureArray[occlusionTexture.source] : null,
            uvIndex: occlusionTexture?.texCoord || 0,
            uvTransform: aoMap_uvTransform,
            mipMap:false,
            isCache:false
          }
          : undefined,
        alphaCutoff: alphaCutoff,
        transparent: transparent,
      });
      this.materialMap.set(index, standardMaterial);
    });
  }
}
export { GltfObject }